package cn.lingyangwl.framework.security.submit;

import cn.lingyangwl.framework.core.http.HttpRequestServletManager;
import cn.lingyangwl.framework.core.utils.IpUtils;
import cn.lingyangwl.framework.core.utils.servlet.ServletUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.hutool.crypto.digest.DigestUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.Redisson;
import org.redisson.api.RLock;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author shenguangyang
 */
@Aspect
public class RepeatSubmitAspect {
    @Resource
    private RepeatSubmitDefinition repeatSubmitDefinition;

    @Resource
    private RepeatSubmitManager repeatSubmitManager;

    @Resource
    private Redisson redisson;

    @Around("@annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
        String keyPrefix = repeatSubmitDefinition.getKeyPrefix();
        boolean res = false;
        if (repeatSubmit.limitType() == RepeatSubmit.Type.IP) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            Class<?> targetClass = method.getDeclaringClass();
            String key = keyPrefix + "::" + DigestUtil.md5Hex(
                    IpUtils.getRequestIp(new HttpRequestServletManager(ServletUtils.getRequestOfNonNull())) +
                            targetClass.getName() + "-" + method.getName() + "-" + repeatSubmitDefinition.getUserId().get());
            // 加分布式锁
            RLock lock = redisson.getLock(key);
            res = lock.tryLock(0, repeatSubmit.lockTime(), TimeUnit.SECONDS);
        } else if (repeatSubmit.limitType() == RepeatSubmit.Type.TOKEN) {
            String token = ServletUtils.getHeaders().get(repeatSubmitDefinition.getHeaderTokenKey());
            if (StringUtils.isEmpty(token)) {
                throw new BizException("非法防重令牌");
            }
            res = repeatSubmitManager.checkToken(token);
        }
        // 当业务处理失败之后, 只能让用户重新走一遍流程, 然后再提交, 否则会出现重复提交问题
        if (!res) {
            throw new BizException(repeatSubmitDefinition.getBaseError());
        }
        return point.proceed();
    }
}
